package com.hundsun.epay.autosimu.api.dom.java;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;

import com.hundsun.epay.autosimu.api.dom.OutputUtility;

/**
 * 方法
 * @author clown
 * @Date 2018-02-04
 */
public class Method extends JavaElement {
	private boolean isSynchronized;   //并发控制
	private String name;   //方法名
	private FullyQualifiedJavaType returnType;   //返回类型
	private List<TypeParameter> typeParameters;   //泛型方法
	private List<Parameter> parameters;   //参数
	private List<FullyQualifiedJavaType> exceptions;   //异常
	private List<String> bodyLines;   //实现体
	private boolean isNative;   //是否是本地方法
	private boolean isConstructor;   //是否是构造函数
	private boolean isDefault;   //forJava8+   default 方法

	public Method(){
		this("clown");    //use a default name
	}
	
	public Method(String name) {
		super();
		this.name = name;
		this.bodyLines = new ArrayList<String>();
		this.exceptions = new ArrayList<FullyQualifiedJavaType>();
		this.typeParameters = new ArrayList<TypeParameter>();
		this.parameters = new ArrayList<Parameter>();
	}
	
	public Method(Method method){
		super(method);
		this.name = method.getName();
		
		this.isSynchronized = method.isSynchronized();
		this.isDefault = method.isDefault();
		this.returnType = method.getReturnType();
		this.isConstructor = method.isConstructor();
		this.isNative = method.isNative();
		
		this.bodyLines = new ArrayList<String>();
		this.exceptions = new ArrayList<FullyQualifiedJavaType>();
		this.typeParameters = new ArrayList<TypeParameter>();
		this.parameters = new ArrayList<Parameter>();
		
		this.typeParameters.addAll(method.getTypeParameters());
		this.parameters.addAll(method.getParameters());
		this.exceptions.addAll(method.getExceptions());
		this.bodyLines.addAll(method.getBodyLines());
	}

	public boolean isSynchronized() {
		return isSynchronized;
	}

	public void setSynchronized(boolean isSynchronized) {
		this.isSynchronized = isSynchronized;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public FullyQualifiedJavaType getReturnType() {
		return returnType;
	}

	public void setReturnType(FullyQualifiedJavaType returnType) {
		this.returnType = returnType;
	}

	public boolean isNative() {
		return isNative;
	}

	public void setNative(boolean isNative) {
		this.isNative = isNative;
	}

	public boolean isConstructor() {
		return isConstructor;
	}

	public void setConstructor(boolean isConstructor) {
		this.isConstructor = isConstructor;
	}

	public boolean isDefault() {
		return isDefault;
	}

	public void setDefault(boolean isDefault) {
		this.isDefault = isDefault;
	}

	public List<TypeParameter> getTypeParameters() {
		return typeParameters;
	}

	public List<Parameter> getParameters() {
		return parameters;
	}

	public List<FullyQualifiedJavaType> getExceptions() {
		return exceptions;
	}

	public List<String> getBodyLines() {
		return bodyLines;
	}
	
	public void addBodyLine(String line){
		this.bodyLines.add(line);
	}
	
	public void addBodyLine(int index, String line){
		this.bodyLines.add(index, line);
	}
	
	public void addBodyLines(Collection<String> lines){
		this.bodyLines.addAll(lines);
	}
	
	public void addBodyLines(int index, Collection<String> lines){
		this.bodyLines.addAll(index, lines);
	}
	
	public void addException(FullyQualifiedJavaType exception){
		this.exceptions.add(exception);
	}
	
	public void addTypeParameter(TypeParameter typeParameter){
		this.typeParameters.add(typeParameter);
	}
	
	public void addTypeParameter(int index, TypeParameter typeParameter){
		this.typeParameters.add(index, typeParameter);
	}
	
	public void addParameter(Parameter parameter){
		this.parameters.add(parameter);
	}
	
	public void addParameter(int index, Parameter parameter){
		this.parameters.add(index, parameter);
	}
	
	public String getFormattedContent(CompilationUnit unit, int indentLevel, boolean interfaceMethod){
		StringBuilder sb = new StringBuilder();
		
		//1.注释注解
		addFormattedJavaDocLines(sb, indentLevel);   //注释
		addFormattedAnnotation(sb, indentLevel);   //注解
		
		//2.方法声明
		OutputUtility.javaIndent(sb, indentLevel);
		//2.1. 修饰符
		if(interfaceMethod){   //接口方法
			if(isStatic()){    //Java8
				sb.append("static ");
			}else if(isDefault){
				sb.append("default ");
			}
		}else{
			sb.append(getVisibility().getDesc());   //可见性
			if(isStatic()){   //静态
				sb.append("static ");
			}
			
			if(isSynchronized){   //并发
				sb.append("synchronized ");
			}
			
			if(isNative){   //本地方法
				sb.append("native "); 
			}else if(bodyLines.isEmpty()){   //抽象方法
				sb.append("abstract ");
			}
		}
		
		//2.2. 泛型
		if (!typeParameters.isEmpty()) {
			sb.append("<");
			boolean first = true;
			for (TypeParameter type : typeParameters) {
				if(first){
					first = false;
				}else{
					sb.append(", ");
				}
				sb.append(type.getFormattedContent(unit));
			}
			sb.append("> ");
		}
		
		//2.3 返回类型
		if(!isConstructor){
			if(returnType == null){
				sb.append("void");
			}else{
				sb.append(JavaDomUtils.calculateTypeName(unit, returnType));
			}
			sb.append(" ");
		}
		
		//2.4.方法名
		sb.append(name);
		
		//2.5.参数
		sb.append("(");
		boolean first = true;
		for (Parameter parameter : parameters) {
			if(first){
				first = false;
			}else{
				sb.append(", ");
			}
			sb.append(parameter.getFormattedContent(unit));
		}
		sb.append(")");
		
		//2.6.异常
		if(!exceptions.isEmpty()){
			sb.append(" throws ");
			first = true;
			for (FullyQualifiedJavaType exception : exceptions) {
				if(first){
					first = false;
				}else{
					sb.append(", ");
				}
				sb.append(JavaDomUtils.calculateTypeName(unit, exception));
			}
		}
		
		if(isNative || bodyLines.isEmpty()){
			sb.append(";");
		}else{
			//2.7.方法体
			sb.append(" {");
			indentLevel++;   //进入方法体，增加一个缩进
			
			ListIterator<String> listInterator = bodyLines.listIterator();
			while(listInterator.hasNext()){
				String line = listInterator.next();    //获取该行内容
				//处理缩进，右括号处理须放在格式化之前，用于支持空程序块
				if(line.startsWith("}")){   //以右大括号开头，减少缩进
					indentLevel --;
				}
				
				//处理格式化
				OutputUtility.newLine(sb);
				OutputUtility.javaIndent(sb, indentLevel);   //进入该行
				sb.append(line);
				
				//处理缩进
				if((line.endsWith("{") && !line.startsWith("switch")) //以左大括号结尾，但不以switch开头，增加缩进
						|| line.endsWith(":")){   //以冒号结尾，增加缩进
					indentLevel ++;
				}
				if(line.startsWith("break")){   //以break开头，需看下一行
					indentLevel --;
					if(listInterator.hasNext()){
						String nextLine = listInterator.next();
						if(nextLine.startsWith("}")){//若下一行是 } ,则不用减少缩进
							indentLevel ++;
						}
						listInterator.previous();   //back
					}
				}
			}
			
			indentLevel --;
			OutputUtility.newLine(sb);
			OutputUtility.javaIndent(sb, indentLevel);
			sb.append("}");
		}
 		return sb.toString();
	}
}
